﻿using System;
using System.Threading;
using System.Threading.Tasks;

namespace zijian666.AnyExtensions;

/// <summary>
/// <seealso cref="Task"/> 扩展方法
/// </summary>
public static class TaskExtensions
{
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Then(this Task task, Action next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            next();
        }
        else
        {
            await Task.Run(next, cancellation);
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task task, Func<T> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            return next();
        }
        else
        {
            return await Task.Run(next, cancellation);
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Then(this Task task, Func<Task> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            await next();
        }
        else
        {
            await Task.Run(next, cancellation);
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task task, Func<Task<T>> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            return await next();
        }
        else
        {
            return await Task.Run(next, cancellation);
        }
    }




    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task<T> task, Action next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            next();
        }
        else
        {
            await Task.Run(next, cancellation);
        }
        return result;
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <typeparam name="TResult">操作后的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<TResult> Then<T, TResult>(this Task<T> task, Func<TResult> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            return next();
        }
        else
        {
            return await Task.Run(next, cancellation);
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task<T> task, Func<Task> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            await next();
        }
        else
        {
            await Task.Run(next, cancellation);
        }
        return result;
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <typeparam name="TResult">操作后的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<TResult> Then<T, TResult>(this Task<T> task, Func<Task<TResult>> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        await task;
        if (cancellation == default)
        {
            return await next();
        }
        else
        {
            return await Task.Run(next, cancellation);
        }
    }




    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task<T> task, Action<T> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            next(result);
        }
        else
        {
            await Task.Run(() => next(result), cancellation);
        }
        return result;
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <typeparam name="TResult">操作后的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, TResult> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            return next(result);
        }
        else
        {
            return await Task.Run(() => next(result), cancellation);
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Then<T>(this Task<T> task, Func<T, Task> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            await next(result);
        }
        else
        {
            await Task.Run(() => next(result), cancellation);
        }
        return result;
    }
    /// <summary>
    /// <paramref name="task"/> 执行成功后执行下一个操作
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <typeparam name="TResult">操作后的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="next">下一个操作</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<TResult> Then<T, TResult>(this Task<T> task, Func<T, Task<TResult>> next, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = next ?? throw new ArgumentNullException(nameof(next));
        var result = await task;
        if (cancellation == default)
        {
            return await next(result);
        }
        else
        {
            return await Task.Run(() => next(result), cancellation);
        }
    }




    /// <summary>
    /// <paramref name="task"/> 执行异常时执行回调
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="onerror">异常回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Catch(this Task task, Action<Exception> onerror, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = onerror ?? throw new ArgumentNullException(nameof(onerror));
        try
        {
            await task;
        }
        catch (Exception e)
        {
            if (cancellation == default)
            {
                onerror(e);
            }
            else
            {
                await Task.Run(() => onerror(e), cancellation);
            }
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行异常时执行回调
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="onerror">异常回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Catch(this Task task, Func<Exception, Task> onerror, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = onerror ?? throw new ArgumentNullException(nameof(onerror));
        try
        {
            await task;
        }
        catch (Exception e)
        {
            if (cancellation == default)
            {
                await onerror(e);
            }
            else
            {
                await Task.Run(() => onerror(e), cancellation);
            }
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行异常时执行回调
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="onerror">异常回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Catch<T>(this Task<T> task, Action<Exception> onerror, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = onerror ?? throw new ArgumentNullException(nameof(onerror));
        try
        {
            return await task;
        }
        catch (Exception e)
        {
            if (cancellation == default)
            {
                onerror(e);
            }
            else
            {
                await Task.Run(() => onerror(e), cancellation);
            }
            throw;
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行异常时执行回调
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="onerror">异常回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Catch<T>(this Task<T> task, Func<Exception, Task> onerror, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = onerror ?? throw new ArgumentNullException(nameof(onerror));
        try
        {
            return await task;
        }
        catch (Exception e)
        {
            if (cancellation == default)
            {
                await onerror(e);
            }
            else
            {
                await Task.Run(() => onerror(e), cancellation);
            }
            throw;
        }
    }




    /// <summary>
    /// <paramref name="task"/> 执行完成后，无论是否异常，都执行回调
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="callback">回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Finally(this Task task, Action callback, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = callback ?? throw new ArgumentNullException(nameof(callback));
        try
        {
            await task;
        }
        finally
        {
            if (cancellation == default)
            {
                callback();
            }
            else
            {
                await Task.Run(callback, cancellation);
            }
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行完成后，无论是否异常，都执行回调
    /// </summary>
    /// <param name="task">当前任务</param>
    /// <param name="callback">回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task Finally(this Task task, Func<Task> callback, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = callback ?? throw new ArgumentNullException(nameof(callback));
        try
        {
            await task;
        }
        finally
        {
            if (cancellation == default)
            {
                await callback();
            }
            else
            {
                await Task.Run(callback, cancellation);
            }
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行完成后，无论是否异常，都执行回调
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="callback">回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Finally<T>(this Task<T> task, Action callback, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = callback ?? throw new ArgumentNullException(nameof(callback));
        try
        {
            return await task;
        }
        finally
        {
            if (cancellation == default)
            {
                callback();
            }
            else
            {
                await Task.Run(callback, cancellation);
            }
        }
    }
    /// <summary>
    /// <paramref name="task"/> 执行完成后，无论是否异常，都执行回调
    /// </summary>
    /// <typeparam name="T">当前任务的返回值类型</typeparam>
    /// <param name="task">当前任务</param>
    /// <param name="callback">回调</param>
    /// <param name="cancellation">取消令牌</param>
    public static async Task<T> Finally<T>(this Task<T> task, Func<Task> callback, CancellationToken cancellation = default)
    {
        _ = task ?? throw new ArgumentNullException(nameof(task));
        _ = callback ?? throw new ArgumentNullException(nameof(callback));
        try
        {
            return await task;
        }
        finally
        {
            if (cancellation == default)
            {
                await callback();
            }
            else
            {
                await Task.Run(callback, cancellation);
            }
        }
    }
}